#include "SQLInsertInto.h"

#include "SQLAssignItem.h"
#include "SQLInsertStatement.h"
#include "SQLExprTableSource.h"
#include "SQLSelect.h"
#include "../SQLExpr.h"
#include "../../../utils/listAddAll.h"

SQLInsertInto::SQLInsertInto()
{
  columns = std::make_shared<std::list<SQLExpr_ptr>>();
  valuesList = std::make_shared<std::list<SQLInsertStatement_ValuesClause_ptr>>();
  partitions = std::make_shared<std::list<SQLAssignItem_ptr>>();
  insertBeforeComments = std::make_shared<std::list<string_ptr>>();
}

void SQLInsertInto::cloneTo(SQLInsertInto_ptr x)
{
  if (tableSource != NULL)
  {
    x->setTableSource(std::dynamic_pointer_cast<SQLExprTableSource>(tableSource->clone()));
  }
  for (SQLExpr_ptr column : *columns)
  {
    SQLExpr_ptr column2 = std::dynamic_pointer_cast<SQLExpr>(column->clone());
    column2->setParent(SharedObject(SQLInsertInto));
    x->columns->push_back(column2);
  }
  if (query != NULL)
  {
    x->setQuery(std::dynamic_pointer_cast<SQLSelect>(query->clone()));
  }
  for (SQLInsertStatement_ValuesClause_ptr v : *valuesList)
  {
    SQLInsertStatement_ValuesClause_ptr v2 = std::dynamic_pointer_cast<SQLInsertStatement_ValuesClause>(v->clone());
    v2->setParent(x);
    x->valuesList->push_back(v2);
  }

  if (hint != NULL)
  {
    x->setHint(std::dynamic_pointer_cast<SQLCommentHint>(hint->clone()));
  }

  x->overwrite = overwrite;
  if (!partitions->empty())
  {
    for (SQLAssignItem_ptr item : *partitions)
    {
      x->addPartition(std::dynamic_pointer_cast<SQLAssignItem>(item->clone()));
    }
  }
}

void SQLInsertInto::addInsertBeforeComment(string_list_ptr comments)
{
  // if (insertBeforeComments == NULL) {
  //     insertBeforeComments = new ArrayList<>();
  // }

  // Utils::ListAddAll<string_ptr , string_ptr >(comments, insertBeforeComments);
  for (auto it : *comments)
  {
    insertBeforeComments->push_back(it);
  }
}

string_list_ptr SQLInsertInto::getInsertBeforeCommentsDirect()
{
  return insertBeforeComments;
}

BOOL_ptr SQLInsertInto::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  auto it_columns = columns->begin();
  for (int i = 0; i < columns->size(); i++)
  {
    std::advance(it_columns, i);
    if ((*it_columns) == expr)
    {
      target->setParent(SharedObject(SQLInsertInto));
      (*it_columns) = target;
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

SQLCommentHint_ptr SQLInsertInto::getHint()
{
  return hint;
}

void SQLInsertInto::setHint(SQLCommentHint_ptr x)
{
  if (x != NULL)
  {
    x->SQLObjectImpl::setParent(SharedObject(SQLInsertInto));
  }
  this->hint = x;
}

SQLObject_ptr SQLInsertInto::clone()
{
  SQLObject_ptr clone_tmp = SharedObject(SQLInsertInto);
  SQLInsertInto_ptr clone_res = std::dynamic_pointer_cast<SQLInsertInto>(clone_tmp);

  return clone_res;
}

string_ptr SQLInsertInto::getAlias()
{
  return tableSource->getAlias();
}

void SQLInsertInto::setAlias(string_ptr alias)
{
  this->tableSource->setAlias(alias);
}

SQLExprTableSource_ptr SQLInsertInto::getTableSource()
{
  return tableSource;
}

void SQLInsertInto::setTableSource(SQLExprTableSource_ptr tableSource)
{
  if (tableSource != NULL)
  {
    tableSource->setParent(SharedObject(SQLInsertInto));
  }
  this->tableSource = tableSource;
}

SQLName_ptr SQLInsertInto::getTableName()
{
  return std::dynamic_pointer_cast<SQLName>(tableSource->getExpr());
}

void SQLInsertInto::setTableName(SQLName_ptr tableName)
{
  this->setTableSource(SQLExprTableSource_ptr(new SQLExprTableSource(tableName)));
}

void SQLInsertInto::setTableSource(SQLName_ptr tableName)
{
  this->setTableSource(SQLExprTableSource_ptr(new SQLExprTableSource(tableName)));
}

SQLSelect_ptr SQLInsertInto::getQuery()
{
  return query;
}

void SQLInsertInto::setQuery(SQLSelectQuery_ptr query)
{
  this->setQuery(SQLSelect_ptr(new SQLSelect(query)));
}

void SQLInsertInto::setQuery(SQLSelect_ptr query)
{
  if (query != NULL)
  {
    query->setParent(SharedObject(SQLInsertInto));
  }
  this->query = query;
}

SQLExpr_list_ptr SQLInsertInto::getColumns()
{
  return columns;
}

void SQLInsertInto::addColumn(SQLExpr_ptr column)
{
  if (column != NULL)
  {
    column->setParent(SharedObject(SQLInsertInto));
  }
  this->columns->push_back(column);
}

SQLInsertStatement_ValuesClause_ptr SQLInsertInto::getValues()
{
  if (valuesList->empty())
  {
    return NULL;
  }
  return *valuesList->begin();
}

void SQLInsertInto::setValues(SQLInsertStatement_ValuesClause_ptr values)
{
  if (valuesList->empty())
  {
    valuesList->push_back(values);
  }
  else
  {
    *valuesList->begin() = values;
  }
}

SQLInsertStatement_ValuesClause_list_ptr SQLInsertInto::getValuesList()
{
  return valuesList;
}

void SQLInsertInto::addValueCause(SQLInsertStatement_ValuesClause_ptr valueClause)
{
  if (valueClause != NULL)
  {
    valueClause->setParent(SharedObject(SQLInsertInto));
  }
  valuesList->push_back(valueClause);
}

string_ptr SQLInsertInto::getColumnsString()
{
  return columnsString;
}

long SQLInsertInto::getColumnsStringHash()
{
  return columnsStringHash;
}

void SQLInsertInto::setColumnsString(string_ptr columnsString, long columnsStringHash)
{
  this->columnsString = columnsString;
  this->columnsStringHash = columnsStringHash;
}

BOOL_ptr SQLInsertInto::isOverwrite()
{
  return overwrite;
}

void SQLInsertInto::setOverwrite(BOOL_ptr overwrite)
{
  this->overwrite = overwrite;
}

void SQLInsertInto::addPartition(SQLAssignItem_ptr partition)
{
  if (partition != NULL)
  {
    partition->setParent(SharedObject(SQLInsertInto));
  }

  // if (partitions == NULL) {
  //     partitions = new ArrayList<SQLAssignItem>();
  // }

  this->partitions->push_back(partition);
}

SQLAssignItem_list_ptr SQLInsertInto::getPartitions()
{
  return partitions;
}
